<!DOCTYPE html>
<html>
<head>
    <title>Physics Diagram</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            background-color: #f0f0f0;
        }
        canvas {
            border: 1px solid black;
            background-color: white;
        }
    </style>
</head>
<body>
    <canvas id="physics-canvas" width="550" height="550"></canvas>
    <script>
        const canvas = document.getElementById('physics-canvas');
        const ctx = canvas.getContext('2d');

        // General settings
        const cx = 275;
        const cy = 260;
        const radius = 120; // This corresponds to 'l'
        const axisLength = 70;
        const arrowHeadLength = 15;

        // Colors and styles
        ctx.strokeStyle = 'black';
        ctx.fillStyle = 'black';

        // --- Helper Functions ---

        /**
         * Draws a spring as a series of semicircles between two points.
         * @param {CanvasRenderingContext2D} ctx The canvas context.
         * @param {number} x1 The starting x-coordinate.
         * @param {number} y1 The starting y-coordinate.
         * @param {number} x2 The ending x-coordinate.
         * @param {number} y2 The ending y-coordinate.
         * @param {number} coils The number of coils in the spring.
         */
        function drawSpring(ctx, x1, y1, x2, y2, coils) {
            const dx = x2 - x1;
            const dy = y2 - y1;
            const length = Math.sqrt(dx * dx + dy * dy);
            const angle = Math.atan2(dy, dx);
            const coilWidth = length / coils;
            const coilRadius = coilWidth / 2;

            ctx.save();
            ctx.translate(x1, y1);
            ctx.rotate(angle);

            ctx.beginPath();
            // The first and last segments are straight
            for (let i = 0; i < coils; i++) {
                // Draws a semi-circle on the "outside" (clockwise direction)
                ctx.arc(i * coilWidth + coilRadius, 0, coilRadius, Math.PI, 0, false);
            }
            ctx.stroke();
            ctx.restore();
        }

        /**
         * Draws a line with an arrowhead.
         * @param {CanvasRenderingContext2D} ctx The canvas context.
         * @param {number} fromX The starting x-coordinate of the line.
         * @param {number} fromY The starting y-coordinate of the line.
         * @param {number} toX The ending x-coordinate (tip of the arrow).
         * @param {number} toY The ending y-coordinate (tip of the arrow).
         * @param {number} headLength The length of the arrowhead sides.
         */
        function drawArrow(ctx, fromX, fromY, toX, toY, headLength) {
            const dx = toX - fromX;
            const dy = toY - fromY;
            const angle = Math.atan2(dy, dx);

            // Draw the line
            ctx.beginPath();
            ctx.moveTo(fromX, fromY);
            ctx.lineTo(toX, toY);
            ctx.stroke();

            // Draw the arrowhead
            ctx.beginPath();
            ctx.moveTo(toX, toY);
            ctx.lineTo(toX - headLength * Math.cos(angle - Math.PI / 6), toY - headLength * Math.sin(angle - Math.PI / 6));
            ctx.lineTo(toX - headLength * Math.cos(angle + Math.PI / 6), toY - headLength * Math.sin(angle + Math.PI / 6));
            ctx.closePath();
            ctx.fill();
        }

        /**
         * Draws text with a subscript.
         * @param {CanvasRenderingContext2D} ctx The canvas context.
         * @param {string} text The main text.
         * @param {string} sub The subscript text.
         * @param {number} x The x-coordinate.
         * @param {number} y The y-coordinate.
         */
        function drawSubscriptText(ctx, text, sub, x, y) {
            const mainFontSize = 22;
            const subFontSize = 16;
            
            ctx.font = `italic ${mainFontSize}px serif`;
            const textMetrics = ctx.measureText(text);
            ctx.fillText(text, x, y);
            
            ctx.font = `italic ${subFontSize}px serif`;
            ctx.fillText(sub, x + textMetrics.width - 4, y + 6);
        }


        // --- Main Drawing Logic ---

        // Define vertex positions (equilateral triangle, 120 degrees apart)
        const angle1 = Math.PI; // 180 degrees (left)
        const angle2 = -Math.PI / 3; // -60 degrees (bottom-right)
        const angle3 = Math.PI / 3; // 60 degrees (top-right)

        const v1 = { x: cx + radius * Math.cos(angle1), y: cy - radius * Math.sin(angle1) };
        const v2 = { x: cx + radius * Math.cos(angle2), y: cy - radius * Math.sin(angle2) };
        const v3 = { x: cx + radius * Math.cos(angle3), y: cy - radius * Math.sin(angle3) };
        
        // Draw internal lines from center to vertices
        ctx.lineWidth = 2.5;
        ctx.beginPath();
        ctx.moveTo(cx, cy);
        ctx.lineTo(v1.x, v1.y);
        ctx.moveTo(cx, cy);
        ctx.lineTo(v2.x, v2.y);
        ctx.moveTo(cx, cy);
        ctx.lineTo(v3.x, v3.y);
        ctx.stroke();

        // Draw springs connecting the vertices
        const numCoils = 18;
        drawSpring(ctx, v1.x, v1.y, v2.x, v2.y, numCoils);
        drawSpring(ctx, v2.x, v2.y, v3.x, v3.y, numCoils);
        drawSpring(ctx, v3.x, v3.y, v1.x, v1.y, numCoils);

        // Draw the axes with arrows
        ctx.lineWidth = 3.5;
        // Axis 1 (at v1, arrow pointing inwards)
        const ax1_start = { x: v1.x - axisLength, y: v1.y };
        drawArrow(ctx, ax1_start.x, ax1_start.y, v1.x, v1.y, arrowHeadLength);

        // Axis 2 (at v2, arrow pointing outwards)
        const ax2_end = { 
            x: v2.x + axisLength * Math.cos(angle2), 
            y: v2.y - axisLength * Math.sin(angle2) 
        };
        drawArrow(ctx, v2.x, v2.y, ax2_end.x, ax2_end.y, arrowHeadLength);

        // Axis 3 (at v3, arrow pointing outwards)
        const ax3_end = { 
            x: v3.x + axisLength * Math.cos(angle3), 
            y: v3.y - axisLength * Math.sin(angle3) 
        };
        drawArrow(ctx, v3.x, v3.y, ax3_end.x, ax3_end.y, arrowHeadLength);

        // Draw labels
        ctx.fillStyle = 'black'; // Ensure text is black

        // Labels x1, x2, x3
        drawSubscriptText(ctx, 'x', '1', v1.x - 45, v1.y + 10);
        drawSubscriptText(ctx, 'x', '2', v2.x - 30, v2.y + 25);
        drawSubscriptText(ctx, 'x', '3', v3.x - 35, v3.y - 10);
        
        // Label 'l'
        ctx.font = 'italic 22px serif';
        const l_pos_x = (cx + v1.x) / 2 + 5;
        const l_pos_y = (cy + v1.y) / 2 - 10;
        ctx.fillText('l', l_pos_x, l_pos_y);

        // Figure caption
        ctx.font = '18px serif';
        ctx.textAlign = 'center';
        ctx.fillText('Fig. 1.94.', canvas.width / 2, canvas.height - 20);

    </script>
</body>
</html>